package com.stox.client.ui.javafx.watchlist.widget;

import java.util.ArrayList;
import java.util.List;

import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.util.Callback;

import com.stox.client.api.core.ClientFactory;
import com.stox.client.api.data.provider.BarClient;
import com.stox.client.api.data.provider.CachingBarClient;
import com.stox.client.api.watchlist.WatchlistEntryClient;
import com.stox.client.core.model.intf.Refreshable;
import com.stox.client.ui.javafx.core.StoxPlatform;
import com.stox.client.ui.javafx.core.util.CSS;
import com.stox.client.ui.javafx.core.util.UI;
import com.stox.client.ui.javafx.widget.AbstractHasScripTableView;
import com.stox.client.ui.javafx.widget.dynamic.column.AbstractCellValueFactory;
import com.stox.client.ui.javafx.widget.dynamic.column.barValue.BarValueColumn;
import com.stox.client.ui.javafx.widget.dynamic.column.barValue.VolumeColumn;
import com.stox.shared.i18n.MessageSource;
import com.stox.shared.model.Watchlist;
import com.stox.shared.model.WatchlistEntry;
import com.stox.shared.model.enumeration.BarValue;

public class WatchlistEntryTableView extends AbstractHasScripTableView<WatchlistEntry> implements Refreshable{

	private final BarClient barClient = new CachingBarClient(ClientFactory.getClient(BarClient.class), 40);
	private final WatchlistComboBox watchlistComboBox;
	private final EventHandler<ActionEvent> deleteEventHandler = new EventHandler<ActionEvent>(){
		public void handle(ActionEvent event) {
			Button button = (Button)event.getSource();
			WatchlistEntry watchlistEntry = (WatchlistEntry)button.getUserData();
			deleteWatchlistEntry(watchlistEntry);
		}
	};
	
	
	@SuppressWarnings("unchecked")
	public WatchlistEntryTableView(WatchlistComboBox watchlistComboBox) {
		super(WatchlistEntry.class);
		this.watchlistComboBox = watchlistComboBox;
		
		watchlistComboBox.valueProperty().addListener(new ChangeListener<Watchlist>(){
			@Override
			public void changed(
					ObservableValue<? extends Watchlist> observable,
					Watchlist oldValue, Watchlist watchlist) {
				if(null != watchlist){
					if((null == watchlist.getEntries() || watchlist.getEntries().isEmpty()) 
							&& null != watchlist.getId() 
							&& 0 != watchlist.getId()){
						new Thread(){
							public void run() {
								List<WatchlistEntry> watchlistEntries = ClientFactory.getClient(WatchlistEntryClient.class).findByWatchlistId(watchlist.getId());
								watchlist.setEntries(watchlistEntries);
								StoxPlatform.runLater(new Runnable(){
									@Override
									public void run() {
										if(null == watchlistEntries || watchlistEntries.isEmpty()){
											getItems().clear();
										}else{
											getItems().setAll(watchlistEntries);
										}
									}
								});
							};
						}.start();
					}else{
						if(null != watchlist.getEntries()){
							getItems().setAll(watchlist.getEntries());
						}
					}
				}
			}
		});
		
		
		
		
		TableColumn<WatchlistEntry, Button> deleteColumn = new TableColumn<>();
		Button deleteAllButton = UI.mediumCrossButton(MessageSource.get("DeleteAll"));
		deleteAllButton.setOnAction(new EventHandler<ActionEvent>(){
			@Override
			public void handle(ActionEvent event) {
				// getItems method can not be used directly, as it gives ConcurrentModificaitonException
				List<WatchlistEntry> watchlistEntries = new ArrayList<>(getItems());
				for(WatchlistEntry watchlistEntry : watchlistEntries){
					deleteWatchlistEntry(watchlistEntry);
				}
			}
		});
		deleteColumn.setGraphic(deleteAllButton);
		UI.style(deleteColumn, CSS.watchlistColumnDelete);
		deleteColumn.setMaxWidth(30);
		deleteColumn.setMinWidth(30);
		deleteColumn.setPrefWidth(30);
		deleteColumn.setCellFactory(new Callback<TableColumn<WatchlistEntry,Button>, TableCell<WatchlistEntry,Button>>() {
			@Override
			public TableCell<WatchlistEntry, Button> call(
					TableColumn<WatchlistEntry, Button> button) {
				return new TableCell<WatchlistEntry, Button>(){
					@Override
					protected void updateItem(Button item, boolean empty) {
						super.updateItem(item, empty);
						setAlignment(Pos.CENTER);
						setCenterShape(true);
						setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
						if(!empty){
							setGraphic(item);
						}else{
							setGraphic(null);
						}
					}
				};
			}
		});
		deleteColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<WatchlistEntry,Button>, ObservableValue<Button>>() {
			@Override
			public ObservableValue<Button> call(
					CellDataFeatures<WatchlistEntry, Button> param) {
				Button button = UI.mediumCrossButton(MessageSource.get("Delete"));
				button.setOnAction(deleteEventHandler);
				button.setUserData(param.getValue());
				return new ReadOnlyObjectWrapper<>(button);
			}
		});
		
		getColumns().addAll( 
				new BarValueColumn<>(BarValue.OPEN, barClient),
				new BarValueColumn<>(BarValue.HIGH, barClient),
				new BarValueColumn<>(BarValue.LOW, barClient),
				new BarValueColumn<>(BarValue.CLOSE, barClient),
				new VolumeColumn<>(barClient),
				deleteColumn);
	}
	
	public void addWatchlistEntry(WatchlistEntry watchlistEntry){
		
		if(null != watchlistEntry 
				&& null != watchlistEntry.getWatchlistId() 
				&& 0 != watchlistEntry.getWatchlistId() 
				&& null != watchlistEntry.getScripId() 
				&& 0 != watchlistEntry.getScripId() 
				&& null != watchlistComboBox){
			
			for(Watchlist watchlist : watchlistComboBox.getItems()){
				if(watchlistEntry.getWatchlistId().equals(watchlist.getId())){
					if(null == watchlist.getEntries()){
						watchlist.setEntries(new ArrayList<WatchlistEntry>());
					}
					watchlist.getEntries().add(watchlistEntry);
					break;
				}
			}
			
			if(null != watchlistComboBox.getValue() 
					&& watchlistEntry.getWatchlistId().equals(watchlistComboBox.getValue().getId())){
				getItems().add(watchlistEntry);
				//FXCollections.sort(getItems());
			}
		}
			
	}
	
	public void deleteWatchlistEntry(WatchlistEntry watchlistEntry){
		ClientFactory.getClient(WatchlistEntryClient.class).delete(watchlistEntry.getId());
		getItems().remove(watchlistEntry);
		watchlistComboBox.getValue().getEntries().remove(watchlistEntry);
	}
	
	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void refresh() {
		StoxPlatform.runLater(new Runnable(){
			@Override
			public void run() {
				if(1 < getColumns().size()){
					for(TableColumn<WatchlistEntry, ?> column : getColumns()){
						if(column.getCellValueFactory() instanceof AbstractCellValueFactory){
							AbstractCellValueFactory<WatchlistEntry,?> cellValueFactory = (AbstractCellValueFactory)column.getCellValueFactory();
							cellValueFactory.clearCache();
						}
					}
					getColumns().get(1).setVisible(false);
					getColumns().get(1).setVisible(true);
				}
			}
		});
	}
	
}